iT邦幫忙

2025 iThome 鐵人賽

DAY 9
0
Vue.js

作為 Angular 專家探索 Vue 3 和 Svelte 5系列 第 9

第 8 天 - 在 Vue 3、Svelte 5 和 Angular 中動態綁定 CSS 類別與樣式

  • 分享至 

  • xImage
  •  

在第8天,我將示範 Vue 3、SvelteKit 與 Angular 如何執行動態的 CSS 類別與樣式綁定。展示中包含 CSS 類別綁定與樣式綁定的範例。當一個項目已購買時,會套用刪除線(strikeout)類別。當項目被標記為高優先時,會使用 priority 類別。加入項目表單中的高優先勾選框被勾選時,字體會因 font-weight 樣式而變粗體 (bold)。

案例 1:列表項目的動態 CSS 類別綁定

Vue 3 範例

<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { ref, computed } from 'vue'

type Item = { id: number; label: string; highPriority: boolean; purchased: boolean }

const items = ref<Item[]>([])

const togglePurchase = (item: Item) => {
  item.purchased = !item.purchased
}
</script>
<template>
    <ul>
      <div class="list-item" v-for="item in items" :key="item.id">
        <li
          :class="[{ priority: item.highPriority }, { strikeout: item.purchased }]"
           @click="togglePurchase(item)"
        >
          {{ item.id }} - {{ item.label }}
        </li>
      </div>
    </ul>
</template>

在 Vue 3 中,元素的 CSS 類別可以綁定到陣列或物件。在此範例中,將一個陣列綁定到 <li> 元素的類別。

{ strikeout: item.purchased } - 當 purchased 屬性為 true 時,strikeout 類別被啟用,否則停用。點擊 <li> 元素時會觸發點擊事件,togglePurchase 函式切換該屬性,導致 strikeout 類別動態套用。

{ priority: item.highPriority } - 同理,當 highPriority 屬性為 true 時,priority 類別被套用。當使用者勾選 High Priority 框並儲存時,該屬性為 true,文字會以不同顏色呈現。

若要傳入物件做類別綁定,寫法是::class="{ priority: item.highPriority, strikeout: item.purchased }"

SvelteKit 範例

<script lang="ts">
    import Icon from '@iconify/svelte';

    type Item = { id: number; label: string; purchased: boolean; higherPriority: boolean };

    let items = $state([] as Item[]);

    function togglePurchased(item: Item) {
        item.purchased = !item.purchased;
        newItem = '';
        newItemHigherPriority = false;
    }
</script>
<ul>
{#each items as item (item.id)}
   <div class="list-item">
       <li class={[item.purchased && 'strikeout', item.higherPriority && 'priority']}>{item.id} - {item.label}</li>
       <button class="btn" onclick={() => togglePurchased(item)} aria-label="purchase an item">
         <Icon icon={!item.purchased ? "ic:baseline-check" : "ic:baseline-close" } />
     </button>
   </div>
{/each}
</ul>

因為 Svelte 編譯器警告 <li> 不應可點擊,因此改用按鈕觸發 togglePurchase 函式切換 purchased 屬性。

如同 Vue 3,元素的 CSS 類別可綁定陣列或物件。這範例傳入陣列到 <li> 元素的類別。

{ item.purchased && 'strikeout' } - 若 purchased 為真,strikeout 類別啟用,否則停用。

{ item.highPriority && 'priority' }- 類似地,priority 類別會於 highPriority 為 true 時套用。當使用者勾選 High Priority 框儲存後,文字呈不同顏色。

若要傳入物件為類別綁定,寫法是::class="{{ priority: item.highPriority, strikeout: item.purchased }}"

Angular 19 範例

import { ChangeDetectionStrategy, Component, computed, signal } from '@angular/core';

type Item = { id: number; label: string; purchased: boolean; highPriority: boolean };

@Component({
  selector: 'app-shopping-cart',
  imports: [],
  template: `
     <ul>
        @for (item of items(); track item.id) {
          @let itemClasses =
            {
              priority: item.highPriority,
              strikeout: item.purchased,
            };
          <div class="list-item">
            <li [class]="itemClasses" (click)="togglePurchase(item)">
                {{ item.id }} - {{ item.label }}
            </li>
          </div>
        }
    </ul>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ShoppingCartComponent {
  items = signal<Item[]>([]);
  newItem = signal('');
  newItemHighPriority = signal(false);

  togglePurchase(item: Item) {
    this.items.update((items) =>
      items.map((element) => (element.id === item.id ? { ...element, purchased: !element.purchased } : element))
    );
    this.newItem.set('');
    this.newItemHighPriority.set(false);
  }
}

Angular 引入了 ``@let` 語法來在模板中建立臨時變數:

@let itemClasses = {
    priority: item.highPriority,
    strikeout: item.purchased,
};

item.highPriority 為 true 時,itemClasses{ priority },當 item.purchased 為 true 時,itemClasses{ strikeout }。兩者都為 true 時,合併為 { priority, strikeout }

類似屬性綁定,使用方括弧語法綁定類別:

[class]="itemClasses"`

這樣會把 itemClasses 傳入 <li> 元素的 CSS 類別。

案例 2:高優先勾選框的動態樣式綁定

Vue 3 範例

newItemHighPriority 是 true 時,High Priority 勾選框的 font-weight 樣式設為粗體(bold),否則為正常(normal):

{ font-weight: newItemHighPriority ? 'bold': 'normal' } - 此樣式物件綁定給 style 屬性,生效為行內樣式。

<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { ref, computed } from 'vue'

const newItemHighPriority = ref(false)

const saveItem = () => { /* 同前邏輯 */ }
</script>
<template>
  <form v-if="isEditing" @submit.prevent="saveItem">
    <label>
      <input type="checkbox" v-model="newItemHighPriority" />
      <span :style="{ 'font-weight': newItemHighPriority ? 'bold' : 'normal' }">
        High Priority</span
      >
    </label>
  </form>
</template>

SvelteKit 範例

newItemHighPriority 為 true 時,High Priority 勾選框字體粗體 (bold),否則為正常 (normal):

style:font-weight={ newItemHighPriority ? 'bold': 'normal' }

<script lang="ts">
    import Icon from '@iconify/svelte';

    let newItemHigherPriority = $state(false);

    async function handleSubmit(event: SubmitEvent) {
    /* 同前邏輯 */
    }
</script>
<form method="POST" onsubmit={handleSubmit}>
   <label>
     <input id="higherPriority" name="higherPriority" type="checkbox" bind:checked={newItemHigherPriority}
      />
      <span style:font-weight={newItemHigherPriority ? 'bold' : 'normal'}> Higher Priority</span>
   </label>
</form>

Angular 19 範例

newItemHighPriority 信號值為 true,High Priority 勾選框的 font-weight 樣式變為粗體 (bold),否則為正常 (normal)。

使用方括弧語法綁定樣式屬性:

[style.fontWeight]="newItemHighPriority ? 'bold': 'normal'"

Angular 使用 camelcase 命名,將 font-weight 轉為 fontWeight

import { ChangeDetectionStrategy, Component, computed, signal } from '@angular/core';
import { FormsModule } from '@angular/forms';

@Component({
  selector: 'app-shopping-cart',
  imports: [FormsModule],
  template: `
      <form (ngSubmit)="saveItem()">
        <label>
          <input type="checkbox" [(ngModel)]="newItemHighPriority" name="newItemHighPriority" />
          <span [style.fontWeight]="newItemHighPriority() ? 'bold' : 'normal'"> High Priority</span>
        </label>
      </form>
  `,
   changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ShoppingCartComponent {
  newItemHighPriority = signal(false);

  saveItem() { /* 同前邏輯 */ }
}

資源

Github Repositories

Github Pages


上一篇
第七天 - 使用內建控管流程語法或指令進行條件渲染
下一篇
第 9 天 - 在 Vue 3、Svelte 5 和 Angular 中屬性綁定
系列文
作為 Angular 專家探索 Vue 3 和 Svelte 519
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言